using System;
using System.Collections.Generic;
using UnityEngine;

namespace LFramework
{
    /// <summary>
    /// 音频管理器
    /// </summary>
    public class AudioManager : IDisposable
    {
        public float MasterVolume { get; private set; }
        public float BGMVolume { get; private set; }
        public float AudioVolume { get; private set; }

        public static string SoundPrefabPath = "Assets/Download/Prefab/Audio/SoundSource.prefab";

        public AudioManager()
        {
            BGMSource = new GameObject("BGMSource", typeof(AudioSource)).GetComponent<AudioSource>();
            BGMSource.transform.SetParent(GameEntry.Instance.AudioContanier.transform);
            BGMSource.outputAudioMixerGroup = GameEntry.Instance.MonsterMixer.FindMatchingGroups("BGM")[0];
        }
        public void Init()
        {
            //先把资源加载到内存
            GameEntry.AssetsLoader.LoadAssetSync<GameObject>(SoundPrefabPath);

            GameEntry.PlayerPrefs.SetFloatHas(PlayerPrefsConstKey.MasterVolume, 1);
            GameEntry.PlayerPrefs.SetFloatHas(PlayerPrefsConstKey.SoundVolume, 1);
            GameEntry.PlayerPrefs.SetFloatHas(PlayerPrefsConstKey.BGMVolume, 1);
            GameEntry.PlayerPrefs.SetBoolHas(PlayerPrefsConstKey.MasterMute, false);

            SetMasterVolume(GameEntry.PlayerPrefs.GetFloat(PlayerPrefsConstKey.MasterVolume));
            SetAudioVolume(GameEntry.PlayerPrefs.GetFloat(PlayerPrefsConstKey.SoundVolume));
            SetBGMVolume(GameEntry.PlayerPrefs.GetFloat(PlayerPrefsConstKey.BGMVolume));
            SetMasterMute(GameEntry.PlayerPrefs.GetBool(PlayerPrefsConstKey.MasterMute));
        }
        public void OnUpdate()
        {
            OnBGMUpdate();
        }

        #region BGM
        public AudioSource BGMSource { get; private set; }

        //目标BGM剪辑
        private AudioClip m_TargetBGMAudioClip;
        //目标BGM是否循环
        private bool m_TargetBGMIsLoop;
        //目标BGM音量
        private float m_TargetBGMClipVolume;

        //BGM淡入淡出过渡音量
        private float m_InterimBGMVolume;

        //是否需要淡入淡出
        private bool m_IsFadeIn;
        private bool m_IsFadeOut;

        private string m_CurrBgmPath = string.Empty;

        public void PlayBGM(string bgmPath, float volume = 1, bool isLoop = true, bool isFadeIn = true, bool isFadeOut = true)
        {
            AudioClip bgmClip = GameEntry.AssetsLoader.LoadAssetSync<AudioClip>(bgmPath);
            if (bgmClip == null)
                return;

            PlayBGM(bgmClip, isLoop, volume, isFadeIn, isFadeOut, bgmPath);
        }
        public void PlayBGM(AudioClip audioClip, bool isLoop, float volume, bool isFadeIn, bool isFadeOut, string bgmPath)
        {
            if (audioClip == null)
            {
                GameEntry.LogError("audioClip==null");
                return;
            }
            m_TargetBGMAudioClip = audioClip;
            m_TargetBGMIsLoop = isLoop;
            m_TargetBGMClipVolume = volume;
            this.m_IsFadeIn = isFadeIn;
            this.m_IsFadeOut = isFadeOut;

            //这里要保证BGM过渡时间小于Asset池释放时间, 否则会在过渡到一半的时候AudioClip就变成null了, 但一般情况下是不会出问题的
            GameEntry.AssetsLoader.UnLoadAssetSync(m_CurrBgmPath);
            m_CurrBgmPath = bgmPath;

            GameEntry.Log(string.Format("PlayBGM, audioClip=={0}, volume=={1}", audioClip, volume));
        }

        public void StopBGM(bool isFadeOut)
        {
            //把音量逐渐变成0 再停止
            m_TargetBGMAudioClip = null;
            this.m_IsFadeOut = isFadeOut;

            //这里要保证BGM过渡时间小于Asset池释放时间, 否则会在过渡到一半的时候AudioClip就变成null了, 但一般情况下是不会出问题的
            GameEntry.AssetsLoader.UnLoadAssetSync(m_CurrBgmPath);
            m_CurrBgmPath = string.Empty;

            GameEntry.Log("StopBGM");
        }

        public void PauseBGM(bool isPause)
        {
            if (isPause)
            {
                BGMSource.Pause();
            }
            else
            {
                BGMSource.UnPause();
            }
            GameEntry.Log(BGMSource.clip + "PauseBGM");

        }

        private void OnBGMUpdate()
        {
            if (BGMSource.clip != m_TargetBGMAudioClip)
            {
                //淡出
                if (m_IsFadeOut && m_InterimBGMVolume > 0)
                {
                    m_InterimBGMVolume -= Time.unscaledDeltaTime * 2;//0.5秒淡出时间
                    SetBGMVolume(BGMVolume);//这里是为了刷新音量
                }
                else
                {
                    //淡出完毕, 或者不需要淡出
                    if (m_TargetBGMAudioClip != null)
                    {
                        //播放新的背景音乐
                        BGMSource.clip = m_TargetBGMAudioClip;
                        BGMSource.loop = m_TargetBGMIsLoop;
                        BGMSource.volume = m_TargetBGMClipVolume;
                        BGMSource.Play();

                        m_InterimBGMVolume = 0;
                        SetBGMVolume(BGMVolume);//这里是为了刷新音量

                    }
                    else
                    {
                        //没新的背景音乐 停止播放
                        BGMSource.Stop();
                        BGMSource.clip = null;
                    }
                }
            }
            else
            {
                //淡入
                if (m_IsFadeIn && m_InterimBGMVolume < 1)
                {
                    m_InterimBGMVolume += Time.unscaledDeltaTime * 2;//0.5秒淡入时间
                    SetBGMVolume(BGMVolume);//这里是为了刷新音量
                }
                else if (m_InterimBGMVolume != 1)
                {
                    m_InterimBGMVolume = 1;
                    SetBGMVolume(BGMVolume);//这里是为了刷新音量
                }
            }
        }
        #endregion

        #region 音效
        private AudioRoutine audioRoutinePrefab;
        private int m_SoundId = 0;
        private Dictionary<int, AudioRoutine> m_SoundDic = new Dictionary<int, AudioRoutine>();

        private int GenSoundId()
        {
            int soundId = ++m_SoundId;
            if (soundId == int.MaxValue)
            {
                soundId = 0;
            }
            return soundId;
        }

        private int PlaySound(string soundPath,bool isLoop = false, float volume = 1, int priority = 128) 
        {
            AudioRoutine soundRoutine = CreateAudioRoutine(isLoop, volume, priority);

            soundRoutine.SetIs3DSound(false,Vector3.zero);
            soundRoutine.Play(soundPath);

            return soundRoutine.SoundId;
        }

        private int PlaySound(string soundPath, Vector3 point, bool isLoop = false, float volume = 1, int priority = 128)
        {
            AudioRoutine soundRoutine = CreateAudioRoutine(isLoop, volume, priority);

            soundRoutine.SetIs3DSound(true,point);
            soundRoutine.Play(soundPath);

            return soundRoutine.SoundId;
        }

        public void StopSound(int soundId) 
        {
            if (m_SoundDic.TryGetValue(soundId, out AudioRoutine soundRoutine))
            {
                soundRoutine.Stop();
                m_SoundDic.Remove(soundId);
            }
        }

        private AudioRoutine CreateAudioRoutine(bool isLoop,float volume, int priority)
        {
            AudioRoutine routine = GameEntry.Pool.GameObjectPool.Spawn(SoundPrefabPath, GameEntry.Instance.AudioContanier.transform).GetComponent<AudioRoutine>();
            
            int soundId = GenSoundId();
            m_SoundDic[soundId] = routine;

            routine.Init(soundId, isLoop, volume, priority);
            return routine;
        }

        #endregion

        public void SetMasterVolume(float volume)
        {
            MasterVolume = volume;
            SetMixerVolume(PlayerPrefsConstKey.MasterVolume, MasterVolume);
            GameEntry.PlayerPrefs.SetFloat(PlayerPrefsConstKey.MasterVolume, MasterVolume);
        }
        public void SetAudioVolume(float volume)
        {
            AudioVolume = volume;
            SetMixerVolume(PlayerPrefsConstKey.SoundVolume, AudioVolume);
            GameEntry.PlayerPrefs.SetFloat(PlayerPrefsConstKey.SoundVolume, AudioVolume);
        }
        public void SetBGMVolume(float volume)
        {
            BGMVolume = volume;
            SetMixerVolume(PlayerPrefsConstKey.BGMVolume, BGMVolume * m_InterimBGMVolume);
            GameEntry.PlayerPrefs.SetFloat(PlayerPrefsConstKey.BGMVolume, BGMVolume);
        }
        private void SetMixerVolume(string key, float volume)
        {
            //因为Mixer内我们要修改的音量是db， 而存档里的音量是0-1形式的百分比， 所以这里要做转换
            volume = (float)(20 * Math.Log10(volume / 1));
            GameEntry.Instance.MonsterMixer.SetFloat(key, volume);
        }

        /// <summary>
        /// 设置根节点(全部)静音
        /// </summary>
        public void SetMasterMute(bool mute)
        {
            SetMasterVolume(mute ? 0 : GameEntry.PlayerPrefs.GetFloat(PlayerPrefsConstKey.MasterVolume));
            GameEntry.PlayerPrefs.SetBool(PlayerPrefsConstKey.MasterMute, mute);
        }

        public void Dispose() 
        {
            GameEntry.AssetsLoader.UnLoadAssetSync(SoundPrefabPath);
        }
    }
}